/*
 * 用于 Hook JNI RegisterNatives 的 Frida 脚本 (最终稳定版)。
 * 此版本通过在 onEnter 中同步复制所有数据，彻底解决了异步回调导致的指针失效和崩溃问题。
 *
 * 使用方法: frida -U -f com.zhiliaoapp.musically -l hook_register_natives.js --no-pause
 */

console.log("[*] JNI RegisterNatives 最终稳定版 Hook 脚本已启动。");

const filterKeywords = [
    "tiktok", "bytedance", "musically", "ss.android", "captcha", 
    "rizon", "turing", "sec", "libtt", "ies", "toutiao", "worker"
];
console.log("[*] 使用过滤器, 关键字: [" + filterKeywords.join(", ") + "]");

const registerNatives_addr = Module.findExportByName(null, "RegisterNatives");

if (registerNatives_addr) {
    console.log("[*] 成功定位 RegisterNatives 地址: " + registerNatives_addr);
    Interceptor.attach(registerNatives_addr, {
        onEnter: function(args) {
            const env = Java.vm.getEnv();
            const jclass = args[1];
            const methods_ptr = args[2];
            const method_count = args[3].toInt32();

            let class_name;
            try {
                class_name = env.getClassName(jclass);
            } catch (e) {
                // 在某些情况下，尤其是在 App 启动早期，获取类名可能会失败
                // console.log("[!] 无法获取类名，跳过本次调用。错误: " + e);
                return;
            }

            const should_hook = filterKeywords.some(keyword => class_name.toLowerCase().includes(keyword));
            if (!should_hook) {
                return;
            }

            // 关键修复：在 onEnter 同步上下文中，立即读取所有需要的数据。
            const methods = [];
            for (let i = 0; i < method_count; i++) {
                const struct_ptr = methods_ptr.add(i * Process.pointerSize * 3);
                const name_ptr = struct_ptr.readPointer();
                const signature_ptr = struct_ptr.add(Process.pointerSize).readPointer();
                const fnPtr = struct_ptr.add(Process.pointerSize * 2).readPointer();

                const method_name = name_ptr.isNull() ? "(null_name)" : name_ptr.readCString();
                const method_sig = signature_ptr.isNull() ? "(null_sig)" : signature_ptr.readCString();
                
                methods.push({
                    name: method_name,
                    sig: method_sig,
                    addr: fnPtr
                });
            }

            // 将复制好的安全数据传递给异步函数去打印
            Java.scheduleOnMainThread(function() {
                console.log("\n[+] 匹配到关键字! RegisterNatives 被调用, 类名: '" + class_name + "' (共 " + method_count + " 个方法)");
                console.log("------------------------------------------------------------");

                methods.forEach(function(method) {
                    const module = Process.findModuleByAddress(method.addr);
                    let module_info = "未找到";
                    if (module) {
                        module_info = `${module.name} (基地址: ${module.base}, 偏移: ${method.addr.sub(module.base)})`;
                    }
                    console.log(`\t- 方法: ${method.name}${method.sig}`);
                    console.log(`\t  Native 地址: ${method.addr}`);
                    console.log(`\t  所属模块: ${module_info}`);
                });

                console.log("------------------------------------------------------------\n");
            });
        }
    });
} else {
    console.log("[!] 无法找到 RegisterNatives 地址，Hook 失败。");
}
